# -*- encoding: utf-8 -*-
##############################################################################
#
##############################################################################

from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_round
from lxml import etree

class MrpProduction(models.Model):
    _inherit = 'mrp.production'

    production_merge_id=fields.Many2one('mrp.production.merge',u'合并单', ondelete='set null')
    order_squence=fields.Integer(u'序列',default=1)
    merge_quantity_done=fields.Float(u'完成数',default=0)
    merge_lot_produced_id = fields.Many2one('stock.production.lot', u'批次号')

    @api.multi
    def create_lot_for_production(self):
        for production in self:
            if not production.merge_lot_produced_id:
                production.merge_lot_produced_id=self.env['stock.production.lot'].create({
                    'product_id': production.product_id.id
                })
            else:
                raise ValidationError(u'已有批次号,不能重复生成!')

class stock_move_lots(models.Model):
    _inherit = 'stock.move.lots'

    merge_line_id=fields.Many2one('mrp.production.merge.line',u'合并单明细', ondelete='set null')

class stock_move(models.Model):
    _inherit = 'stock.move'

    production_merge_id=fields.Many2one('mrp.production.merge',u'合并单', ondelete='set null')
    production_merge_line_id=fields.Many2one('mrp.production.merge.line',u'合并明细', ondelete='set null')
    merged = fields.Boolean(string=u'已合并', default=False)

class mrp_production_merge(models.Model):
    _name = 'mrp.production.merge'
    _inherit = 'mail.thread'

    name = fields.Char(u"名称", readonly=True)
    description = fields.Text(u"描述")
    picking_track_number = fields.Char(u"内部参考",related='merge_move_raw_ids.picking_track_number')
    product_attention = fields.Html(string=u"注意事项")
    state = fields.Selection([('draft', u'草稿'), ('open', u'执行中'),
                              ('close', u'完成'), ('cancel', u'取消')],
                             string=u'状态', required=True, track_visibility='onchange', copy=False, default='draft')
    date_start = fields.Date(string=u'创建时间', default=fields.Date.today)
    user_id = fields.Many2one('res.users', string=u'责任人', track_visibility='onchange')

    mrp_production_id=fields.Many2one('mrp.production',u"生产单",related='mrp_production_move_raw_ids.raw_material_production_id')
    mrp_production_ids=fields.One2many('mrp.production','production_merge_id',u"生产单", ondelete='set null')
    mrp_production_move_raw_ids=fields.One2many('stock.move','production_merge_id',u"原始投料明细", ondelete='set null')
    merge_move_raw_ids=fields.One2many('mrp.production.merge.line','production_merge_id',u"投料明细")
    production_attribute_line_ids = fields.One2many("product.production.attribute.line","production_merge_id")
    picking_type_id = fields.Many2one("stock.picking.type", string=u"作业类型", required=True)
    department_id = fields.Many2one("hr.department", string="部门")

    @api.model
    def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
        res = super(mrp_production_merge, self).fields_view_get(
            view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
        if view_type == "form" and not self.env.user.has_group("mrp_production_adjust.group_mrp_production_adjust"):
            doc = etree.XML(res['arch'])
            xpaths = [
                "//field[@name='production_attribute_line_ids']",
            ]
            for path in xpaths:
                for node in doc.xpath(path):
                    node.set('modifiers', '{"readonly": true}')
            res['arch'] = etree.tostring(doc)
        return res

    @api.onchange('mrp_production_ids')
    def onchange_mrp_production_ids(self):
        if self.mrp_production_ids:
            for production in self.mrp_production_ids:
                if not production.production_merge_id:
                    production.production_merge_id = self.id
                    for move_line in production.move_raw_ids:
                        move_line.production_merge_id = self.id
                    self.state='draft'

    @api.model
    def create(self, vals):
        if 'name' not in vals or vals['name'] == _('New'):
            picking_type = self.env["stock.picking.type"].browse(vals.get("picking_type_id"))
            if not picking_type:
                raise UserError(u"必须提供作业类型才能创建合并单")
            if not picking_type.production_merge_sequence_id:
                raise UserError(u"%s上未设置：生产合并单编号序列" % picking_type.name)
            vals['name'] = picking_type.production_merge_sequence_id.next_by_id() or _('New')
        merge = super(mrp_production_merge, self).create(vals)
        return merge

    @api.multi
    def set_cancel(self):
        for merge in self:
            for mrp_production in merge.mrp_production_ids:
                mrp_production.production_merge_id=None
            for production_move_line in merge.mrp_production_move_raw_ids:
                production_move_line.production_merge_id=None
                production_move_line.production_merge_line_id=None
                production_move_line.merged=False
            merge.state='cancel'


    @api.multi
    def remark_all_done(self):
        for mrp_production in self.mrp_production_ids:
            if mrp_production.state in ['confirmed','planned','progress']:
                return False
        return True


    @api.multi
    def set_done(self):
        move_lot_obj = self.env['stock.move.lots']
        for mrp_production in self.mrp_production_ids:
            if mrp_production.state in ['done','cancel']:
                continue
            can_post=False
            if mrp_production.merge_quantity_done==0:
                continue
            if mrp_production.product_id.tracking <>'none' and not mrp_production.merge_lot_produced_id:
                continue
            for finished_move in mrp_production.move_finished_ids:
                # 这里是需要考虑多对多生产的情况
                if finished_move.product_id==mrp_production.product_id:
                    move_lot_obj.create({
                        'move_id': finished_move.id,
                        'production_id': mrp_production.id,
                        'lot_id': mrp_production.merge_lot_produced_id.id,
                        'quantity_done': mrp_production.merge_quantity_done,
                    })
                    can_post=True
                    mrp_production.merge_lot_produced_id=None
                    mrp_production.merge_quantity_done=0
            if can_post:
                mrp_production.post_inventory()
            if mrp_production.check_to_done:
                mrp_production.button_mark_done()
        if self.remark_all_done():
            self.state='close'
        return True

    @api.multi
    def multi_post_inventory(self):
        move_lot_obj=self.env['stock.move.lots']
        for merge_move in self.merge_move_raw_ids:
            if merge_move.quantity_ready==0:
                continue
            move_raw_qty=0
            for move_rew in merge_move.mrp_production_move_raw_ids:
                if move_rew.state=='done' or move_rew.state=='cancel':
                    continue
                move_raw_qty+=move_rew.product_uom_qty
            if move_raw_qty==0:
                continue
            # 得考虑批次号的问题。
            # avag_qty=merge_move.quantity_ready/move_raw_qty
            for move_rew in merge_move.mrp_production_move_raw_ids:
                if move_rew.state == 'done' or move_rew.state == 'cancel':
                    continue
                # 如果用批次号，就通过批次号来进行比较和创建。
                # 如果合并单上批次号数量大于需求数，那直接创建就好；如果小于，就需要循环创建。
                if merge_move.has_tracking:
                    for lot in merge_move.active_move_lot_ids:
                        # 批次号数量>=需求数,直接搞定本明细
                        if lot.quantity_done>=move_rew.product_uom_qty:
                            move_lot_obj.create({
                                'move_id':move_rew.id,
                                'production_id':move_rew.raw_material_production_id.id,
                                'lot_id':lot.lot_id.id,
                                'quantity_done':move_rew.product_uom_qty,
                            })
                            lot.quantity_done-=move_rew.product_uom_qty
                        elif lot.quantity_done>0:
                            move_lot_obj.create({
                                'move_id': move_rew.id,
                                'production_id': move_rew.raw_material_production_id.id,
                                'lot_id': lot.lot_id.id,
                                'quantity_done': lot.quantity_done,
                            })
                            lot.quantity_done = 0
                        else:
                            lot.unlink()
                # move_rew.quantity_done=avag_qty*move_rew.product_uom_qty
        for production in self.mrp_production_ids:
            production.post_inventory()
        return True

    @api.multi
    def set_open(self):
        merge_line_obj=self.env['mrp.production.merge.line']
        self.merge_move_raw_ids=None
        for production in self.mrp_production_ids:
            for move_line in production.move_raw_ids:
                if move_line.state=='cancel':
                    continue
                has=False
                for line in self.merge_move_raw_ids:
                    if move_line.product_id ==line.product_id:
                        # line.quantity+=move_line.product_uom_qty
                        line.quantity_done+=move_line.quantity_done
                        move_line.production_merge_line_id=line.id
                        has=True
                if not has:
                    merge_line=merge_line_obj.create({
                        'production_merge_id':self.id,
                        'product_id':move_line.product_id.id,
                        'name':move_line.name,
                        # 'quantity':move_line.product_uom_qty,
                        'quantity_ready':0.0,
                        'quantity_done':move_line.quantity_done,
                        'uom_id':move_line.product_uom.id,
                    })
                    move_line.production_merge_line_id=merge_line
                move_line.production_merge_id=self.id
        self.state='open'
        return


class mrp_production_merge_lots(models.Model):
    _name = 'mrp.production.merge.lots'
    _description = "Quantities to Process by lots"

    merge_line_id = fields.Many2one('mrp.production.merge.line', u'合并明细')
    lot_id = fields.Many2one(
        'stock.production.lot', u'批次号',
        domain="[('product_id', '=', product_id)]")
    lot_produced_id = fields.Many2one('stock.production.lot', 'Finished Lot')
    lot_produced_qty = fields.Float('Quantity Finished Product', help="Informative, not used in matching")
    quantity = fields.Float('To Do', default=1.0)
    quantity_done = fields.Float('Done')
    product_id = fields.Many2one(
        'product.product', 'Product',
        readonly=True, related="merge_line_id.product_id", store=True)
    plus_visible = fields.Boolean("Plus Visible", compute='_compute_plus')

    def _compute_plus(self):
        for movelot in self:
            if movelot.merge_line_id.product_id.tracking == 'serial':
                movelot.plus_visible = (movelot.quantity_done <= 0.0)
            else:
                movelot.plus_visible = (movelot.quantity == 0.0) or (movelot.quantity_done < movelot.quantity)

    @api.multi
    def do_plus(self):
        self.ensure_one()
        self.quantity_done = self.quantity_done + 1
        return self.merge_line_id.split_move_lot()

    @api.multi
    def do_minus(self):
        self.ensure_one()
        self.quantity_done = self.quantity_done - 1
        return self.merge_line_id.split_move_lot()


class mrp_production_merge_line(models.Model):
    _name = 'mrp.production.merge.line'

    production_merge_id = fields.Many2one('mrp.production.merge', u'合并单')
    product_id = fields.Many2one('product.product', string=u'产品', required=True)
    name = fields.Text(string=u'描述', required=True)
    note = fields.Text(string=u'备注')

    quantity = fields.Float(compute='_compute_quantity', string=u'待投数量')
    quantity_ready_done = fields.Float(string=u'执行数量', default=0.0)
    quantity_ready = fields.Float(
        u'执行数量', compute='_qty_done_compute', inverse='_qty_done_set',
        digits=dp.get_precision('Product Unit of Measure'))
    quantity_done = fields.Float(compute='_compute_quantity',string=u'完成数量')

    picking_track_number = fields.Char(u'内部参考')
    product_available = fields.Float(related='product_id.qty_available', string=u'在手')
    product_incoming = fields.Float(related='product_id.incoming_qty', string=u'在途')

    uom_id = fields.Many2one('product.uom', string=u'单位', required=True)
    mrp_production_move_raw_ids = fields.One2many('stock.move', 'production_merge_line_id', u"原始投料明细")

    has_tracking = fields.Selection(related='product_id.tracking', string=u'需要批次号')
    move_lot_ids = fields.One2many('mrp.production.merge.lots', 'merge_line_id', string=u'批次')
    active_move_lot_ids = fields.One2many('mrp.production.merge.lots', 'merge_line_id', string=u'批次')

    @api.multi
    @api.depends('move_lot_ids', 'move_lot_ids.quantity_done', 'quantity_ready_done')
    def _qty_done_compute(self):
        for merge_line in self:
            if merge_line.has_tracking != 'none':
                merge_line.quantity_ready = sum(merge_line.move_lot_ids.mapped(
                    'quantity_done'))  # TODO: change with active_move_lot_ids?
            else:
                merge_line.quantity_ready = merge_line.quantity_ready_done

    @api.multi
    def _qty_done_set(self):
        for merge_line in self:
            if merge_line.has_tracking == 'none':
                merge_line.quantity_ready_done = merge_line.quantity_ready

    @api.multi
    def save(self):
        return True

    @api.depends('mrp_production_move_raw_ids')
    def _compute_quantity(self):
        for line in self:
            quantity=0
            quantity_done=0
            for move in line.mrp_production_move_raw_ids:
                if move.state<>'cancle':
                    quantity+=move.product_uom_qty
                    if move.state=='done':
                        quantity_done+=move.product_uom_qty
            line.quantity=quantity
            line.quantity_done=quantity_done



    @api.onchange('product_id')
    def onchange_product_id(self):
        product=self.product_id
        if not self.uom_id:
            self.uom_id = product.uom_id.id
        name = product.display_name
        if product.description_sale:
            name += '\n' + product.description_sale
        self.name = name

    @api.multi
    def cancel_line(self):
        for line in self:
            for move in line.mrp_production_move_raw_ids:
                if move.state<>'done':
                    move.action_cancel()
        return True

    @api.multi
    def split_move_lot(self):
        ctx = dict(self.env.context)
        is_done=False
        self.ensure_one()
        view = self.env.ref('mrp_production_merge.view_merge_line_lots')
        serial = (self.has_tracking == 'serial')
        only_create = False  # Check picking type in theory
        show_reserved = any([x for x in self.move_lot_ids if x.quantity > 0.0])
        if self.quantity==self.quantity_done:
            is_done=True
        ctx.update({
            'serial': serial,
            'only_create': only_create,
            'create_lots': True,
            'state_done': is_done,
            'show_reserved': show_reserved,
        })
        result = {
            'name': _('Register Lots'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mrp.production.merge.line',
            'views': [(view.id, 'form')],
            'view_id': view.id,
            'target': 'new',
            'res_id': self.id,
            'context': ctx,
        }
        return result